<?php



namespace app\controller;



use think\facade\Cache;

use Lcobucci\JWT\Builder;

use Lcobucci\JWT\Signer\Hmac\Sha256;

use Lcobucci\JWT\Parser;

use Lcobucci\JWT\ValidationData;





class Token extends Base

{

    public function initialize()

    {

        parent::initialize();
    }





    //
    // 验证接口数据
    // @param $userid 用户信息是否可用
    // @param $token 用户信息是否可用
    // @param $isuser array 是否验证用户信息
    // @return bool
    //
    public static function apisecurity($isuser = true)

    {
        //合并post|get 防止param有多余信息,如没有任何参数则返回
        $param = @array_merge(_post(), _get());
        //验证用户信息
        if (!request()->header('accessToken')) {
            _Result('应用凭证未发送!', 400);
        }
        $accessToken = Token::signTosecret(request()->header('accessToken'));
        if (!$accessToken) {
            _Result('应用凭证错误!', 400);
        }
        $redisapp = setReids(2,$accessToken['app_id'],'',true);
        if (request()->header('accessToken') != $redisapp) {
            _Result('应用凭证错误!', 400);
        }
        if ($isuser) {
            if (empty($param) && !request()->header('token')) {
                _Result('访问异常!', 400);
            }
            //验证token是否有效 token及userid
            if (!request()->header('token')) {
                _Result('用户登录状态已失效，请重新登录!', 400);
            }
            $token =  Token::validateToken(request()->header('token'), true);
            if (!$token) {
                _Result('用户未登录，请去先登录!', 400);
            }
            // $cache = Cache::get('token' . $token);
            $redisdata = setReids(1, 'users-token-' . $token, '', true);
            if (!$redisdata) {
                _Result('登录状态异常', 400);
            }
            if (strpos($redisdata, request()->header('token')) === false) {
                _Result('登录状态异常', 400);
            }
        }
    }





    //
    // 创建Token
    // @param $uid 需要保存的用户身份标识
    // @return String
    //
    public static function createToken($userid = null)
    {

        $signer = new Sha256();
        $token = (new Builder())->setIssuer('http://www.hljmdd.cn')
            ->setAudience('http://www.hljmdd.cn')
            ->setId('mdd-4f1g23a12aa', true) //自定义标识
            ->setIssuedAt(time()) //当前时间
            ->setExpiration(time() + (86400 * 30)) //token有效期时长
            ->set('uid', $userid)
            ->sign($signer, 'e24463fa21e497d7')
            ->getToken();
        return (string) $token;
    }





    //
    //检测Token是否过期与篡改
    //@param token
    //@param return
    //@return boolean/string
    //
    public static function validateToken($tokens = null, $return = false)
    {
        try {
            $token = (new Parser())->parse((string) $tokens);
        } catch (\Throwable $th) {
            _Result('用户登录状态已失效，请重新登录!', 400);
            return false;
        }
        $uid = $token->getClaim('uid');
        // if ($uid != $userid) {
        //     return false; //用户id不正确
        // }
        $signer = new Sha256();
        if (!$token->verify($signer, 'e24463fa21e497d7')) {
            return false; //签名不正确
        }
        $validationData = new ValidationData();
        $validationData->setIssuer('http://www.hljmdd.cn');
        $validationData->setAudience('http://www.hljmdd.cn');
        $validationData->setId('mdd-4f1g23a12aa'); //自字义标识
        if ($return) {
            return $uid;
        } else {
            return $token->validate($validationData);
        }
    }



    //
    //检测secret
    //@param secret
    //@param return
    //@return boolean/array
    //
    public static function validateSecret($secret = '', $return = false)
    {
        $secret = Token::signTosecret($secret);
        if (!$secret) {
            return false;
        }
        if ($return) {
            return $secret;
        }
        return true;
    }



    //设置用户登录cache
    public static function setcache($id = 0, $token = '')
    {
        $cache = Cache::get('token' . $id);
        if ($cache) {
            $cachearray = @explode('|', $cache);
            foreach ($cachearray ? $cachearray : [] as $key => $value) {
                $exp = str2arr($value);
                if (!$exp[1]) {
                    unset($cachearray[$key]);
                } else {
                    if ($exp[1] <= time()) {
                        unset($cachearray[$key]);
                    }
                }
            }
            //删掉cache里第一条补进去最后一条
            if (@count($cachearray) >= 100) {
                array_shift($cachearray);
            };
            if ($token) {
                array_push($cachearray, ($token . ',' . (time() + 2592000)));
                Cache::set('token' . $id, arr2str($cachearray, '|'), 2592000);
            } else {
                Cache::set('token' . $id, arr2str($cachearray, '|'), 2592000);
            }
        } else {
            if ($token) {
                Cache::set('token' . $id, $token . ',' . (time() + 2592000), 2592000);
            }
        }
    }


    //获取ID
    public function getUsersId($tokens)
    {
        try {
            $token = (new Parser())->parse((string) $tokens);
        } catch (\Throwable $th) {
            _Result('用户登录状态已失效，请重新登录!', 400);
            return false;
        }
        $uid = $token->getClaim('uid');
        if (!$uid) {
            _Result('用户登录状态已失效，请重新登录!', 400);
            return false;
        }
        return $uid;
    }


    //
    //创建secret
    //@param $userid
    //@param $storeid
    //@param $openid
    //@param $appid
    //@return String
    //
    public static function createSecret($data = [])
    {
        $str = @json_encode($data);
        $hex = "";
        for ($i = 0; $i < strlen($str); $i++) {
            $hex .= dechex(ord($str[$i]));
        }
        $hex = strtoupper($hex);
        $base = base64_encode($hex);
        $len = strlen($base);
        $part = ($len / 4);
        $arr = str_split($base, $part);
        return arr2str($arr, '.') . '.' . str_replace('=', '', base64_encode(md5(time()) . uniqid()));
    }





    /**
     *base64转十六进制转字符串转数组函数
     *@pream string $hex='616263';
     */
    public static function signTosecret($str = "")
    {
        $array = str2arr($str, '.');
        unset($array[4]);
        $base = arr2str($array, '');
        $hex = base64_decode($base);
        $str = '';
        for ($i = 0; $i < strlen($hex) - 1; $i += 2) {
            $str .= chr(hexdec($hex[$i] . $hex[$i + 1]));
        }
        return @json_decode($str, true);
    }
}
